package qs.controls
{
	import flash.geom.Point;
	import flash.display.DisplayObject;
	import mx.core.IUIComponent;

	/** the amount of space, in pixels, between invidual items */
	[Style(name="spacing", type="Number", inherit="no")]
	[Style(name="padding", type="Number", inherit="no")]
	[Style(name="horizontalAlign", type="String", enumeration="left,center,right", inherit="no")]
	[Style(name="horizontalGap", type="Number", inherit="no")]
	[Style(name="verticalGap", type="Number", inherit="no")]
		
	public class TileLayout extends Layout
	{
		// fields
		private var _rowLength:int = 16;
		private var _maxRowLength:Number = Number.MAX_VALUE;
		private var _colLength:int;
		private var _tileWidth:int;
		private var _tileHeight:int;
		private var _userTileWidth:Number;
		private var _userTileHeight:Number;
		
		// Constructor
		public function TileLayout()
		{
		}
		
		// Getters and setters
				
		//-----------------------------------------------------------------
		public function set maxRowLength(value:int):void
		{
			_maxRowLength = value;
			if (container)
			{
				container.invalidateSize();
				container.invalidateDisplayList();
			}
		}
		public function get maxRowLength():int
		{
			return _maxRowLength;
		}
		//-----------------------------------------------------------------
		public function set tileWidth(value:Number):void
		{
			_userTileWidth = value;
			if (container)
			{
				container.invalidateSize();
				container.invalidateDisplayList();
			}
		}
		public function get tileWidth():Number
		{
			return isNaN(_userTileWidth)? _tileWidth:_userTileWidth;
		}
		//-----------------------------------------------------------------
		public function set tileHeight(value:Number):void
		{
			_userTileHeight = value;
			if (container)
			{
				container.invalidateSize();
				container.invalidateDisplayList();
			}
		}
		public function get tileHeight():Number
		{
			return isNaN(_userTileHeight)? _tileHeight:_userTileHeight;
		}
		//-----------------------------------------------------------------

		
		private function get spacingWidthDefault():Number
		{
			var result:Number = getStyle("spacing");
			if(isNaN(result))
				result = 20;
			return result;
		}
		private function get hGapWithDefault():Number
		{
			var result:Number = getStyle("horizontalGap");
			if(isNaN(result))
				result = 4;
			return result;
		}
		private function get vGapWithDefault():Number
		{
			var result:Number = getStyle("verticalGap");
			if(isNaN(result))
				result = 4;
			return result;
		}
		private function get paddingWidthDefault():Number
		{
			var result:Number = getStyle("padding");
			if(isNaN(result))
				result = 40;
			return result;
		}
		
		// ILayout interface
		override public function getMeasuredSize():Point
		{
			// Can't execute this if we aren't attached to a container.
			if (!container)
				return new Point(0, 0);
				
			_tileWidth = 0;
			_tileHeight = 0;
			
			// first, calculate the largest width/height of all the items, since we'll have to make all of the items
			// that size
			if(container.renderers.length > 0)
			{
				if(isNaN(_userTileHeight) || isNaN(_userTileWidth))
				{
					for(var i:int=0;i<container.renderers.length;i++)
					{
						var itemRenderer:IUIComponent = container.renderers[i];
						_tileWidth = Math.ceil(Math.max(_tileWidth,itemRenderer.getExplicitOrMeasuredWidth()));
						_tileHeight = Math.ceil(Math.max(_tileHeight,itemRenderer.getExplicitOrMeasuredHeight()));
					}
				}
				if(!isNaN(_userTileHeight))
					_tileHeight = _userTileHeight;
				if(!isNaN(_userTileWidth))
					_tileWidth = _userTileWidth;
			}
			// square them off
			//_tileWidth = Math.max(_tileWidth,_tileHeight);
			//_tileHeight = _tileWidth;
						
			var itemsInRow:Number = Math.min(container.renderers.length,Math.min(_maxRowLength,_rowLength));
			
			var spacing:Number = spacingWidthDefault;
			var hGap:Number = hGapWithDefault;
			var vGap:Number= vGapWithDefault;
			
			var defaultColumnCount:Number = Math.ceil(container.renderers.length / Math.min(_maxRowLength,_rowLength));

			var measuredWidth : Number = itemsInRow * _tileWidth + (itemsInRow - 1) * hGap;
			var measuredHeight : Number = defaultColumnCount*_tileHeight + (defaultColumnCount-1)*vGap;
	
			return new Point(measuredWidth, measuredHeight);
		}
		
		override public function findItemAt(px:Number, py:Number, seamAligned:Boolean):Number
		{
			// Can't execute this if we aren't attached to a container.
			if (!container)
				return NaN;
				
			var gPt:Point = container.localToGlobal(new Point(px,py));
						
			px += container.horizontalScrollPosition;
			py += container.verticalScrollPosition;
			
			var spacing:Number = spacingWidthDefault;
			var hGap:Number = hGapWithDefault;
			var vGap:Number= vGapWithDefault;
			var padding:Number = paddingWidthDefault;
			
			var targetWidth:Number = unscaledContainerWidth -2*padding + hGap;
			var rowLength:Number = Math.max(1,Math.min(container.renderers.length,Math.min(_maxRowLength,Math.floor(targetWidth/(_tileWidth+hGap)) )));
			var colLength:Number = (rowLength == 0)? 0:(Math.ceil(container.renderers.length / rowLength));

			var hAlign:String = getStyle("horizontalAlign");
			var leftSide:Number = (hAlign == "left")? 	padding:
								  (hAlign == "right")? 	(unscaledContainerWidth - (rowLength * _tileWidth + (rowLength-1) * hGap + 2*padding)):
													  	(unscaledContainerWidth - (rowLength * _tileWidth + (rowLength-1) * hGap + 2*padding))/2
									
			var rowPos:Number = (px-padding - leftSide) / (_tileWidth + hGap);
			var colPos:Number = (py-vGap/2) / (_tileHeight + vGap);
			rowPos = (seamAligned)? Math.round(rowPos):Math.floor(rowPos);
			colPos = Math.floor(colPos);
						
			if(seamAligned)
			{
				rowPos = Math.max(0,Math.min(rowPos,rowLength));
				colPos = Math.max(0,Math.min(colPos,colLength));
				var result:Number = colPos * rowLength + rowPos;						
				return Math.min(container.dataProvider.length,result);
								
			}
			else
			{
				if(rowPos >= rowLength || rowPos < 0)
					return NaN;
				if(colPos >= colLength || colPos < 0)
					return NaN;
				result = colPos * rowLength + rowPos;																	
				if(result > container.dataProvider.length)
					return NaN;
				var r:DisplayObject = container.renderers[result];
				if(r.hitTestPoint(gPt.x,gPt.y,true) == false)
					return NaN;					
				return result;
			}
		}
		
		override public function generateLayout():void
		{
			var spacing:Number = spacingWidthDefault;
			var hGap:Number = hGapWithDefault;
			var vGap:Number= vGapWithDefault;
			var padding:Number = paddingWidthDefault;
			var targetWidth:Number = unscaledContainerWidth - 2*padding + hGap;
			var rowLength:Number = Math.max(1,Math.min(container.renderers.length,Math.min(_maxRowLength,Math.floor(targetWidth/(hGap + _tileWidth)) )));
			var colLength:Number = Math.ceil(container.renderers.length / rowLength);
			
			var hAlign:String = getStyle("horizontalAlign");
			
			var leftSide:Number = (hAlign == "left")? 	padding:
								  (hAlign == "right")? 	(unscaledContainerWidth - (rowLength * _tileWidth + (rowLength-1) * hGap + 2*padding)):
													  	(unscaledContainerWidth - (rowLength * _tileWidth + (rowLength-1) * hGap + 2*padding))/2
			
			var positionFunc:Function = function(r:int,c:int,offset:Number):void
			{			
				var idx:int = c*rowLength + r;
				if(idx >= container.renderers.length)
					return;								
				var renderer:IUIComponent = container.renderers[idx];
				var target:LayoutTarget = animator.targetFor(renderer);//targets[idx];
				target.scaleX = target.scaleY = 1;
				target.item = renderer;
				target.unscaledWidth = (isNaN(renderer.percentWidth)? renderer.getExplicitOrMeasuredWidth():renderer.percentWidth/100*_tileWidth);
				target.unscaledHeight = renderer.getExplicitOrMeasuredHeight();
				target.x = offset + r * (_tileWidth + hGap) + _tileWidth/2 - target.unscaledWidth/2;
				target.y = vGap + c * (_tileHeight + vGap)+ _tileHeight/2 - target.unscaledHeight/2;
				target.animate = true;					
			}

			var insertRowPos:Number = container.dragTargetIndex % rowLength;
			var insertColPos:Number = Math.floor(container.dragTargetIndex / rowLength);
			
			for(var c:int = 0;c<colLength;c++)			
			{
				if(c == insertColPos)
				{
					for(var r:int = 0;r<insertRowPos;r++)
					{
						positionFunc(r,c,leftSide);
					}
					for(r = insertRowPos;r<rowLength;r++)
					{
						positionFunc(r,c,leftSide + 2*padding);
					}
				}
				else
				{
					for(r = 0;r<rowLength;r++)
					{
						positionFunc(r,c,leftSide + padding);
					}
				}
			}
		}
	}
}